package cc.rengu.redp.base.config;

import cc.rengu.redp.common.properties.RedpProperties;
import cc.rengu.redp.common.properties.SwaggerProperties;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.Collections;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;
/**
 * @author wx
 */
@Configuration
public class SwaggerConfig {
    @Autowired
    private RedpProperties properties;

    @Bean
    public Docket swaggerApi() {
        SwaggerProperties swagger = properties.getSwagger();
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(properties.isTestMode())
                .select()
//                .apis(RequestHandlerSelectors.basePackage(swagger.getBasePackage()))
                .apis(
                        basePackage(swagger.getBasePackage())
                )
                .paths(PathSelectors.any())
                .paths(PathSelectors.regex("^(?!login).*$"))
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts())
                .apiInfo(apiInfo(swagger));
    }

    private List<SecurityScheme> securitySchemes() {
        return newArrayList(new ApiKey("Authentication", "Authentication", "header"));
    }

    private List<SecurityContext> securityContexts() {
        return newArrayList(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .build()
        );
    }

    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return newArrayList(
                new SecurityReference("Authentication", authorizationScopes));
    }

    private ApiInfo apiInfo(SwaggerProperties swagger) {
        return new ApiInfo(
                swagger.getTitle(),
                swagger.getDescription(),
                swagger.getVersion(),
                null,
                new Contact(swagger.getAuthor(), swagger.getUrl(), swagger.getEmail()),
                swagger.getLicense(), swagger.getLicenseUrl(), Collections.emptyList());
    }

    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        Predicate<RequestHandler> handlerPredicate = input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
        return handlerPredicate;
    }
    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage)     {
        Function<Class<?>, Boolean> function = input -> {
            // 循环判断匹配
            for (String strPackage : basePackage.split(StringPool.COMMA)) {
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
        return function;
    }

    private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
        return Optional.fromNullable(input.declaringClass());
    }
}
